package com.example.gobang.controller;

import com.example.gobang.constant.Constants;
import com.example.gobang.manager.OnlineUserManager;
import com.example.gobang.manager.RoomManager;
import com.example.gobang.model.*;
import com.example.gobang.service.RoomService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

@Component
@Slf4j
public class RoomController extends TextWebSocketHandler {
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private OnlineUserManager onlineUserManager;
    @Autowired
    private RoomService roomService;
    @Autowired
    private RoomManager roomManager;
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 游戏准备

        // 获取用户信息
        UserInfo userInfo = (UserInfo) session.getAttributes().get(Constants.USER_INFO);
        // 判断用户是否登录
        if(userInfo == null) {
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(Result.noLogin())));
            return;
        }
        // 获取游戏房间
        Room room = roomManager.getRoomByUserId(userInfo.getUserId());
        // 玩家和房间未成功匹配
        if(room == null) {
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(Result.fail("用户尚未匹配到房间！"))));
            return;
        }

        // 判断用户是否多开
        if(onlineUserManager.getFromHall(userInfo.getUserId()) != null || onlineUserManager.getFromRoom(userInfo.getUserId()) != null) {
            // 用户已经登录过
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(Result.repeatConnection())));
            log.info("已禁止玩家 {} 多开游戏", userInfo.getUserName());
            return;
        }

        // 将用户设置为在线状态
        onlineUserManager.enterGameRoom(userInfo.getUserId(), session);

        // 将两个玩家加入到游戏房间中 进行加锁操作
        synchronized (room) {
            if (room.getUser1() == null) {
                // 第一个玩家尚未加入房间
                room.setUser1(userInfo);
                // 将 玩家1 设为先手
                room.setWhiteUser(userInfo.getUserId());
                log.info("房间 {} 玩家1 {} 已就绪", room.getRoomId(), userInfo.getUserName());
                System.out.println("玩家1：" + room.getUser1() + "玩家2：" + room.getUser2());
                return;
            }

            if (room.getUser2() == null) {
                // 第二个玩家尚未加入房间
                room.setUser2(userInfo);
                log.info("房间 {} 玩家2 {} 已就绪", room.getRoomId(), userInfo.getUserName());
                // 通知 玩家1 和 玩家2 游戏已准备就绪
                notifyGameReady(room, room.getUser1(), room.getUser2());
                notifyGameReady(room, room.getUser2(), room.getUser1());
                return;
            }
        }
        // 若还有玩家尝试进入同一房间，则提示房间已满
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(Result.fail("房间已满！"))));
    }

    private void notifyGameReady(Room room, UserInfo thisUser, UserInfo thatUser) throws IOException {
        GameReadyResponse readyResponse = new GameReadyResponse();
        readyResponse.setRoomId(room.getRoomId());
        readyResponse.setThisUserId(thisUser.getUserId());
        readyResponse.setThatUserId(thatUser.getUserId());
        readyResponse.setWhiteUser(room.getWhiteUser());
        WebSocketSession session = onlineUserManager.getFromRoom(thisUser.getUserId());
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(Result.success(readyResponse, Constants.GAME_READY))));
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 处理落子请求

        // 获取用户信息
        UserInfo userInfo = (UserInfo) session.getAttributes().get(Constants.USER_INFO);
        // 判断用户是否登录
        if(userInfo == null) {
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(Result.noLogin())));
        }
        // 处理请求
        String payload = message.getPayload();
        GameRequest request = objectMapper.readValue(payload, GameRequest.class);
        // 根据请求落子
        roomService.putChess(request, userInfo);
    }


    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        // 获取用户信息
        UserInfo userInfo = (UserInfo) session.getAttributes().get(Constants.USER_INFO);
        // 判断用户是否登录
        if(userInfo == null) {
            return;
        }
        // 获取游戏房间中存储的玩家信息
        WebSocketSession onlineSession = onlineUserManager.getFromRoom(userInfo.getUserId());
        if(session == onlineSession) {
            // 当前玩家下线，对手直接胜利
            notifyThatUserWin(userInfo);
            // 玩家下线
            onlineUserManager.exitGameRoom(userInfo.getUserId());
            log.info("玩家 {} 从游戏房间退出", userInfo.getUserName());
        }

    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        // 获取用户信息
        UserInfo userInfo = (UserInfo) session.getAttributes().get(Constants.USER_INFO);
        // 判断用户是否登录
        if(userInfo == null) {
            return;
        }
        // 获取游戏房间中存储的玩家信息
        WebSocketSession onlineSession = onlineUserManager.getFromRoom(userInfo.getUserId());
        if(session == onlineSession) {

            // 玩家下线
            onlineUserManager.exitGameRoom(userInfo.getUserId());

        }
        // 当前玩家下线，对手胜利
        notifyThatUserWin(userInfo);
        log.info("玩家 {} 从游戏房间退出", userInfo.getUserName());
        System.out.println("roomController:" + onlineUserManager.getFromRoom(userInfo.getUserId()));
    }

    private void notifyThatUserWin(UserInfo userInfo) throws IOException{
        // 查找下线玩家所在房间
        Room room = roomManager.getRoomByUserId(userInfo.getUserId());
        // 判断房间是否已经被销毁
        if(room == null) {
            return;
        }
        // 查找到对手 并判断对手是否已经下线
        UserInfo thatUser = (room.getUser1() == userInfo) ? room.getUser2() : room.getUser1();
        if(thatUser == null) {
            return;
        }

        WebSocketSession thatUserSession = onlineUserManager.getFromRoom(thatUser.getUserId());
        if(thatUserSession == null) {
            return;
        }
        // 返回响应
        GameResponse response = new GameResponse(room.getRoomId(), thatUser.getUserId(), thatUser.getUserId());
        thatUserSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(Result.success(response, Constants.PUT_CHESS))));

        log.info("房间{} 玩家 {} 胜利！", room.getRoomId(), thatUser.getUserId());
        // 更新玩家分数
        roomService.updateScore(thatUser.getUserId(), userInfo.getUserId());
    }
}
